package com.example.basic.web.service.notice.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.basic.base.impl.BaseEntityServiceImpl;
import com.example.basic.exception.ServiceException;
import com.example.basic.utils.IdUtils;
import com.example.basic.utils.StringUtils;
import com.example.basic.web.enums.AuditEnum;
import com.example.basic.web.enums.DataCodeEnum;
import com.example.basic.web.enums.DeviceAddressEnum;
import com.example.basic.web.enums.OutParamStatusEnum;
import com.example.basic.web.mapper.notice.OutNoticeMapper;
import com.example.basic.web.model.binding.BindingInfo;
import com.example.basic.web.model.device.Device;
import com.example.basic.web.model.notice.OutNotice;
import com.example.basic.web.model.pharmOut.PharmOutRecord;
import com.example.basic.web.model.pharmStock.PharmStock;
import com.example.basic.web.model.remains.RemainsInfo;
import com.example.basic.web.model.terminal.TerminalRecord;
import com.example.basic.web.model.zoneDepot.ZoneDepot;
import com.example.basic.web.response.OutNoticeResponse;
import com.example.basic.web.service.binding.BindingInfoService;
import com.example.basic.web.service.common.CommonService;
import com.example.basic.web.service.dataCode.DataCodeService;
import com.example.basic.web.service.notice.OutNoticeService;
import com.example.basic.web.service.pharmOut.PharmOutRecordService;
import com.example.basic.web.service.pharmStock.PharmStockService;
import com.example.basic.web.service.remains.RemainsInfoService;
import com.example.basic.web.service.terminal.TerminalRecordService;
import com.example.basic.web.service.transTask.TransTaskService;
import com.example.basic.web.service.zoneDepot.ZoneDepotService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static com.example.basic.utils.CheckUtil.notNull;


@Service
public class OutNoticeServiceImpl extends BaseEntityServiceImpl<OutNoticeMapper, OutNotice> implements OutNoticeService {

    @Resource
    private OutNoticeMapper outNoticeMapper;

    @Resource
    private DataCodeService dataCodeService;

    @Resource
    private CommonService commonService;

    @Resource
    private HttpServletRequest request;

    @Resource
    private PharmOutRecordService pharmOutRecordService;

    @Resource
    private PharmStockService pharmStockService;

    @Resource
    private RemainsInfoService remainsInfoService;

    @Resource
    private TerminalRecordService terminalRecordService;

    @Resource
    private BindingInfoService bindingInfoService;

    @Resource
    private TransTaskService transTaskService;

    @Resource
    private ZoneDepotService zoneDepotService;

    /**
     * 批量新增
     * @param outNoticeList
     * @return
     */
    @Override
    public Boolean batchAdd(List<OutNotice> outNoticeList) {
        notNull(outNoticeList,"出库通知单不能为空");

        outNoticeList.forEach(outNotice -> {
            checkParams(outNotice);
        });

        List<String> remainsCodes = outNoticeList.stream().map(OutNotice::getRemainsCode).collect(Collectors.toList());

        //判断遗体是否已出库
        LambdaQueryWrapper<OutNotice> lqw = new LambdaQueryWrapper<>();
        lqw.in(OutNotice::getRemainsCode,remainsCodes);
        List<OutNotice> local = this.mapper.selectList(lqw);

        if(local.size() > 0){
            throw new ServiceException("该遗体已存在出库通知单");
        }

        //生成出库通知单编码
        List<String> outNoticeCode = dataCodeService.generateDataCodeNoList(DataCodeEnum.OUT_NOTICE_CODE.getType(),outNoticeList.size());

        for (int i = 0; i < outNoticeList.size(); i++) {
            outNoticeList.get(i).setOutNoticeCode(outNoticeCode.get(i));
            preCreate(outNoticeList.get(i));
            outNoticeList.get(i).setId(IdUtils.fastUUID());
            outNoticeList.get(i).setStatus(AuditEnum.ADD.getType());

//            outNoticeList.get(i).setOperPerson((String) request.getAttribute("userCode"));
            outNoticeList.get(i).setOperPerson("测试");
        }

        return saveBatch(outNoticeList);
    }

    /**
     * 保存或者修改
     * @param outNotice 模型
     * @return
     */
    @Override
    public OutNotice modify(OutNotice outNotice) {

        //参数校验
        checkParams(outNotice);
        notNull(outNotice.getOutNoticeCode(), "通知单编码不能为空");

        OutNotice localNotice = this.detail(outNotice.getOutNoticeCode());
        if(localNotice.getStatus().equals(AuditEnum.AUDIT.getType())){
            throw new ServiceException("已审核的通知单不允许修改");
        }

        outNotice.setId(localNotice.getId());
        preUpdate(outNotice);


        this.save(outNotice);
        return detail(outNotice.getOutNoticeCode());
    }

    /**
     * 参数校验
     * @param outNotice
     */
    private void checkParams(OutNotice outNotice) {
        notNull(outNotice,"实体不能为空");
        notNull(outNotice.getRemainsCode(),"遗体编码不能为空");
        notNull(outNotice.getInPharmCode(),"入库单据号不能为空");
    }

    /**
     * 详情
     * @param outNoticeCode 出库通知单编码
     * @return
     */
    @Override
    public OutNotice detail(String outNoticeCode) {
        notNull(outNoticeCode, "出库通知单编码不能为空");

        LambdaQueryWrapper<OutNotice> lqw = new LambdaQueryWrapper<>();
        lqw.eq(OutNotice::getOutNoticeCode,outNoticeCode);
        return  this.mapper.selectOne(lqw);
    }

    /**
     * 删除
     * @param outNoticeCode 出库通知单编码
     * @return
     */
    @Override
    public int delete(String outNoticeCode) {
        notNull(outNoticeCode,"出库通知单编码不能为空");

        OutNotice outNotice = detail(outNoticeCode);
        if(outNotice == null){
            throw new ServiceException("未查询到当前数据");
        }

        if(outNotice.getStatus().equals(AuditEnum.AUDIT.getType())){
            throw new ServiceException("已审核的通知单无法删除");
        }

        return this.mapper.deleteById(outNotice.getId());
    }

    /**
     * 审核/取消审核  zzl
     * @param outNotice 出库通知单
     * @return
     */
    @Override
    public int auditOrCancel(OutNotice outNotice) {
        notNull(outNotice,"出库通知单不能为空");
        notNull(outNotice.getOutNoticeCode(),"出库通知单编码不能为空");
        notNull(outNotice.getCremationRoom(),"火化间不能为空");

        OutNotice localNotice = detail(outNotice.getOutNoticeCode());

        if(localNotice == null){
            throw new ServiceException("未查询到当前数据");
        }

        //审核/取消审核
        localNotice.setStatus(AuditEnum.AUDIT.getType());
        localNotice.setAuditTime(commonService.getDataBaseTime());
        localNotice.setAuditPerson((String) request.getAttribute("userCode"));
        localNotice.setAdmireHall(outNotice.getAdmireHall());
        localNotice.setCremationRoom(outNotice.getCremationRoom());
        localNotice.setOutDatetime(commonService.getDataBaseTime());

        //更新库存出库时间
        PharmStock pharmStock = pharmStockService.queryByRemainsCode(localNotice.getRemainsCode());
        pharmStock.setOutDatetime(localNotice.getOutDatetime());
        pharmStock.setOutOperPerson(localNotice.getAuditPerson());
        pharmStockService.modify(pharmStock);

        //审核通过，生成出库单
        PharmOutRecord pharmOutRecord = new PharmOutRecord();
        pharmOutRecord.setOutNoticeCode(outNotice.getOutNoticeCode());
        pharmOutRecord.setStatus(OutParamStatusEnum.WAIT.getType());
        pharmOutRecord.setRemainsCode(pharmStock.getRemainsCode());
        pharmOutRecordService.add(pharmOutRecord);

        //获取绑定关系，更新绑定关系单据
        BindingInfo bindingInfo = bindingInfoService.detail(pharmStock.getRemainsCode());
        bindingInfo.setDocumentNo(pharmOutRecord.getOutPharmCode());
        bindingInfoService.modify(bindingInfo);

        //获取遗体信息
        RemainsInfo remainsInfo = remainsInfoService.detail(localNotice.getRemainsCode());
        //创建作业任务
        //任务流程 接驳台->运送车->转运接驳台->可升降转运车->特殊处理->瞻仰->火化->结束返回
        this.cremationStruct(pharmStock, remainsInfo, pharmOutRecord.getOutPharmCode());

        preUpdate(localNotice);
        this.mapper.updateById(localNotice);

        //任务开始
        try {
            transTaskService.sendTransTask(pharmOutRecord.getOutPharmCode());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return 1;
    }

    /**
     * 任务流程 接驳台->运送车->转运接驳台->可升降转运车->特殊处理->瞻仰->火化->结束返回
     * @param pharmStock
     * @param remainsInfo
     */
    private void cremationStruct(PharmStock pharmStock, RemainsInfo remainsInfo, String documentNo) {

        List<TerminalRecord> terminalRecordList = new ArrayList<>();

        TerminalRecord terminalRecord = new TerminalRecord();

        //初始点位
        ZoneDepot zoneDepot = zoneDepotService.detail(pharmStock.getDepotCode());

        //开始点位
        String beginAddress = zoneDepot.getDepotPoint();

        //结束点位
        String endAddress = DeviceAddressEnum.STAGING_AREA.getType();

        Integer sortNo = 1;

        terminalRecord.setOperType("入口暂存区");
        terminalRecord.setRemainsCode(pharmStock.getRemainsCode());
        terminalRecord.setInstructStart(beginAddress);
        terminalRecord.setInstructEnd(endAddress);
        terminalRecord.setStatus("0");
        terminalRecord.setSortNo(sortNo);
        terminalRecord.setDocumentNo(documentNo);
        terminalRecord.setInstructAddress(endAddress);
        terminalRecordList.add(terminalRecord);

        beginAddress = DeviceAddressEnum.STAGING_AREA.getType();
        sortNo += 1;

        //是否需要特殊处理
        if (StringUtils.notEmptyParams(remainsInfo.getSpecialHandle())) {
            String[] split = remainsInfo.getSpecialHandle().split(",");
            for (int i = 0; i < split.length; i++) {


                //单据状态
                String documnentStatus = "";
                String operType = "";
                if (split[i].equals("1")) {
                    documnentStatus = "4";
                    //整容
                    endAddress = DeviceAddressEnum.MAKEUP.getType();
                    operType = DeviceAddressEnum.MAKEUP.getDesc();
                } else if (split[i].equals("3")) {
                    documnentStatus = "5";
                    //化妆
                    endAddress = DeviceAddressEnum.DISINFECT.getType();
                    operType = DeviceAddressEnum.DISINFECT.getDesc();
                }else {
                    continue;
                }

                terminalRecord = new TerminalRecord();
                terminalRecord.setOperType(operType);
                terminalRecord.setRemainsCode(pharmStock.getRemainsCode());
                terminalRecord.setInstructStart(beginAddress);
                terminalRecord.setInstructEnd(endAddress);
                terminalRecord.setStatus("0");
                terminalRecord.setSortNo(sortNo);
                terminalRecord.setDocumentNo(documentNo);
                terminalRecord.setDocumentStatus(documnentStatus);
                terminalRecord.setInstructAddress(endAddress);
                terminalRecordList.add(terminalRecord);
                sortNo+=1;
                beginAddress = endAddress;
                if(i == split.length - 1){
                    break;
                }
            }
        }

        //是否需要瞻仰
        if(!"3".equals(remainsInfo.getAdmire())){

            terminalRecord.setOperType("瞻仰暂存区");
            terminalRecord.setRemainsCode(pharmStock.getRemainsCode());
            terminalRecord.setInstructStart(beginAddress);
            terminalRecord.setInstructEnd(DeviceAddressEnum.STAGING_AREA.getType());
            terminalRecord.setStatus("0");
            terminalRecord.setSortNo(sortNo);
            terminalRecord.setDocumentNo(documentNo);
            terminalRecord.setInstructAddress(endAddress);
            terminalRecordList.add(terminalRecord);

            beginAddress = DeviceAddressEnum.STAGING_AREA.getType();
            sortNo += 1;

            terminalRecord = new TerminalRecord();
            terminalRecord.setOperType("遗体瞻仰");
            terminalRecord.setRemainsCode(pharmStock.getRemainsCode());
            terminalRecord.setInstructStart(beginAddress);
            terminalRecord.setInstructEnd(DeviceAddressEnum.ADMIRE.getType());
            terminalRecord.setStatus("0");
            terminalRecord.setSortNo(sortNo);
            terminalRecord.setDocumentNo(documentNo);
            terminalRecord.setDocumentStatus("7");
            terminalRecord.setInstructAddress(DeviceAddressEnum.ADMIRE.getType());

            terminalRecordList.add(terminalRecord);

            beginAddress = DeviceAddressEnum.ADMIRE.getType();
            sortNo += 1;
        }

        //火化间
        //-1层提升机->提升机接驳台->火化间提升机
        terminalRecord = new TerminalRecord();
        terminalRecord.setOperType("-1层提升机");
        terminalRecord.setRemainsCode(pharmStock.getRemainsCode());
        terminalRecord.setInstructStart(beginAddress);
        terminalRecord.setInstructEnd(DeviceAddressEnum.TRANS_HOIST.getType());
        terminalRecord.setStatus("0");
        terminalRecord.setSortNo(sortNo);
        terminalRecord.setDocumentNo(documentNo);
        terminalRecord.setInstructAddress(DeviceAddressEnum.TRANS_HOIST.getType());
        terminalRecordList.add(terminalRecord);

        beginAddress = DeviceAddressEnum.TRANS_HOIST.getType();

        terminalRecord = new TerminalRecord();
        terminalRecord.setOperType("火化间提升机");
        terminalRecord.setRemainsCode(pharmStock.getRemainsCode());
        terminalRecord.setInstructStart(beginAddress);
        terminalRecord.setInstructEnd(DeviceAddressEnum.CREMATION.getType());
        terminalRecord.setStatus("0");
        terminalRecord.setSortNo(sortNo);
        terminalRecord.setDocumentNo(documentNo);
        terminalRecord.setInstructAddress(DeviceAddressEnum.CREMATION.getType());
        terminalRecordList.add(terminalRecord);


        terminalRecordService.batchAdd(terminalRecordList);

    }

    /**
     * 出库通知单列表
     * @param queryPage 分页
     * @param searchParam 遗体名称，拼音码，五笔码
     * @param sex 性别
     * @param pharmCode 库房编码
     * @param zoneCode 分区编码
     * @param depotCode 库位编码
     * @param beginTime 开始日期
     * @param endTime 结束日期
     * @return
     */
    @Override
    public IPage<OutNoticeResponse> queryList(Page<OutNoticeResponse> queryPage, String searchParam, String sex, String pharmCode, String zoneCode, String depotCode, String beginTime, String endTime) {

        return this.mapper.queryList(queryPage,searchParam,sex,pharmCode,zoneCode,depotCode,beginTime,endTime);
    }

}
